<?php

namespace Xin\Setting;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Xin\Setting\Exceptions\NotFountSettingItemException;

class RemoteRepository extends AbstractRepository
{
	use HasHttpRequests {
		HasHttpRequests::httpRequest as performRequest;
	}

	/**
	 * @param array $config
	 */
	public function __construct(array $config)
	{
		parent::__construct($config);

		$httpClientConfig = $config['http_client'] ?? [];
		if (isset($httpClientConfig['base_uri'])) {
			$httpClientConfig['base_uri'] = rtrim($httpClientConfig['base_uri'], '/') . '/';
		}

		$this->setHttpClient(new Client($httpClientConfig));
	}

	/**
	 * @inheritDoc
	 */
	protected function httpRequest($uri, $method = 'GET', $options = [])
	{
		$response = $this->performRequest($uri, $method, $options);

		return json_decode($response->getBody()->getContents(), true);
	}

	/**
	 * @inheritDoc
	 */
	public function hasInfo($key)
	{
		$response = $this->httpGet('has', [
			'key' => $key,
		]);

		return $response['exists'];
	}

	/**
	 * @inheritDoc
	 * @throws GuzzleException
	 */
	public function info($key, $fail = false)
	{
		$result = $this->httpGet('get', [
			'keys' => $key,
			'fail' => $fail,
		]);

		if (!$fail) {
			return $result;
		}

		if (!isset($result)) {
			throw new NotFountSettingItemException($key);
		}

		return $result[$key];
	}

	/**
	 * @inheritDoc
	 * @throws GuzzleException
	 */
	public function infos(array $keys)
	{
		return $this->httpGet('info', [
			'keys' => implode(",", $keys),
		]);
	}

	/**
	 * @inerhitDoc
	 */
	public function get($key, $default = null)
	{
		return $this->httpGet('get', [
			'keys' => $key,
		]);
	}

	/**
	 * @inheritDoc
	 * @throws GuzzleException
	 */
	public function getMultiple($keys, $default = null)
	{
		return $this->httpGet('get', [
			'keys' => $keys,
		]);
	}

	/**
	 * @inheritDoc
	 * @throws GuzzleException
	 */
	public function set($key, $value, $isMerge = true)
	{
		return $this->httpPostJson('set', [
			'key' => $key,
			'value' => $value,
			'merge' => $isMerge,
		]);
	}

	/**
	 * @inheritDoc
	 * @throws GuzzleException
	 */
	public function setMultiple(array $settings)
	{
		foreach ($settings as $key => $value) {
			$this->set($key, $value);
		}
	}

	/**
	 * @inheritDoc
	 * @throws GuzzleException
	 */
	public function upsert($key, $info, bool $serialize = false)
	{
		return $this->httpPostJson('put', [
			'key' => $key,
			'info' => $info,
		]);
	}

	/**
	 * @inheritDoc
	 * @throws GuzzleException
	 */
	public function multipleUpsert(array $items, bool $detaching = false, bool $serialize = false)
	{
		foreach ($items as $key => $value) {
			$this->upsert($key, $value, $serialize);
		}
	}

	/**
	 * @inheritDoc
	 * @throws GuzzleException
	 */
	public function all(array $search = [], array $options = [])
	{
		return $this->httpGet('all', $search);
	}


	/**
	 * @inheritDoc
	 * @throws GuzzleException
	 */
	public function delete($key)
	{
		$response = $this->httpPostJson('remove', [
			'key' => $key,
		]);

		return $response != null;
	}


	/**
	 * @inheritDoc
	 * @throws GuzzleException
	 */
	public function deletes(array $keys)
	{
		foreach ($keys as $key) {
			$this->delete($key);
		}
	}

	/**
	 * @inheritDoc
	 * @throws GuzzleException
	 */
	protected function getExistsKeys(array $keys)
	{
		return $this->httpGet('exist_keys', [
			'keys' => implode(",", $keys),
		]);
	}


	/**
	 * @inheritDoc
	 * @throws GuzzleException
	 */
	protected function create(array $data, bool $serialize = false)
	{
		return $this->httpPostJson('create', $data);
	}


	/**
	 * @inheritDoc
	 * @throws GuzzleException
	 */
	protected function update($key, array $data, bool $serialize = false)
	{
		$data['key'] = $key;
		return $this->httpPostJson('update', $data);
	}


	/**
	 * @inheritDoc
	 * @throws GuzzleException
	 */
	public function paginate(array $search = [], array $options = [])
	{
		$this->httpGet('paginate', array_merge($search, $options));
	}
}
